package com.nail.api.customMake.service.impl;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.nail.api.customMake.bean.Indent;
import com.nail.api.customMake.bean.Message;
import com.nail.api.customMake.bean.PayLog;
import com.nail.api.customMake.service.IInDentService;
import com.nail.api.customMake.service.IMessageService;
import com.nail.api.customMake.service.IPaypalService;
import com.nail.api.customMake.service.IpayLogService;
import com.nail.api.user.bean.User;
import com.nail.api.user.dao.IUserDao;
import com.nail.config.PaypalConfig;
import com.nail.enumeration.PaypalPaymentIntent;
import com.nail.enumeration.PaypalPaymentMethod;
import com.nail.service.impl.BaseService;
import com.paypal.api.payments.Amount;
import com.paypal.api.payments.FuturePayment;
import com.paypal.api.payments.Payer;
import com.paypal.api.payments.Payment;
import com.paypal.api.payments.PaymentExecution;
import com.paypal.api.payments.RedirectUrls;
import com.paypal.api.payments.Transaction;
import com.paypal.base.codec.binary.Base64;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;


@Service
public class PaypalServiceImpl extends BaseService implements IPaypalService{
	Logger logger = Logger.getLogger(this.getClass());

	@Autowired
	private APIContext apiContext;

	@Autowired
	private IMessageService messageService;

	@Autowired
	private IpayLogService payLogService;

	@Autowired
	private IInDentService inDentService;

	@Autowired
	PaypalConfig paypalConfig;

	@Autowired
	private IUserDao userDao;

	static Map<Integer,Object> orderTypeMap = new HashMap<>();

	@Value("${paypal.client.app}")
	private String clientId;
	@Value("${paypal.client.secret}")
	private String clientSecret;
	@Value("${paypal.client.accessToken}")
	private String accessToken;
	@Value("${paypal.mode}")
	private String mode;
	
	private Long tokenLifeTime = null;

	static{
		orderTypeMap.put(0,"nail stickers");
		orderTypeMap.put(1,"phone case");
		orderTypeMap.put(2,"nail plates");
	}
	
	@Scheduled(fixedRate=30000)  
	public void refreshAPIContext(){
		if(tokenLifeTime == null){
			setTokenLifeTime();
		}
		if(tokenLifeTime != null && new Date().getTime() >= tokenLifeTime){
			apiContext = new APIContext(clientId,clientSecret,mode);
			logger.info("*****************刷新了APIContext*******");
			logger.info("*****************刷新了APIContext,新accessToken:"+apiContext.getAccessToken()+"*******");
			setTokenLifeTime();
		}
	}

	public Payment createPayment(
			Double total,
			String currency,
			PaypalPaymentMethod method,
			PaypalPaymentIntent intent,
			String description,
			String cancelUrl,
			String successUrl) throws PayPalRESTException {

		Amount amount = new Amount();
		amount.setCurrency(currency);
		amount.setTotal(String.format("%.2f", total));

		Transaction transaction = new Transaction();
		transaction.setDescription(description);
		transaction.setAmount(amount);

		List<Transaction> transactions = new ArrayList<>();
		transactions.add(transaction);

		Payer payer = new Payer();
		payer.setPaymentMethod(method.toString());

		Payment payment = new Payment();
		payment.setIntent(intent.toString());
		payment.setPayer(payer);
		payment.setTransactions(transactions);
		RedirectUrls redirectUrls = new RedirectUrls();
		redirectUrls.setCancelUrl(cancelUrl);
		redirectUrls.setReturnUrl(successUrl);
		payment.setRedirectUrls(redirectUrls);		
		return payment.create(apiContext);
	}
	

	public void setTokenLifeTime(){
		OkHttpClient client = new OkHttpClient();
		try {
			MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
			RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials");
			Request request = new Request.Builder()
					.url(mode.equals("live")?"https://api.paypal.com/v1/oauth2/token":"https://api.sandbox.paypal.com/v1/oauth2/token")
					.post(body)
					.addHeader("Authorization",  "Basic " + generateBase64String(clientId + ":" + clientSecret))
					.addHeader("content-type", "application/x-www-form-urlencoded")
					.build();

			Response response = client.newCall(request).execute();
			String responseBody = response.body().string();
			System.out.println(responseBody);
			JSONObject jsonObject = JSONObject.parseObject(responseBody);
			String accessToken = jsonObject.get("token_type") + " " + jsonObject.get("access_token");
			Integer time = (Integer)jsonObject.get("expires_in");
			tokenLifeTime = new Date().getTime() + time*1000;
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			logger.info("********accessToken:" + accessToken+"********");
			logger.info("********过期时间:" + sdf.format(new Date(tokenLifeTime))+"********");
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
		}
	}


	public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException{
		Payment payment = new Payment();
		payment.setId(paymentId);
		PaymentExecution paymentExecute = new PaymentExecution();
		paymentExecute.setPayerId(payerId);
		apiContext = apiContext.setRequestId(UUID.randomUUID().toString());
		logger.info("*************重新生成PayPal-Request-Id*******"+apiContext.getRequestId()+"********************");
		return payment.execute(apiContext, paymentExecute);
	}

	@Transactional
	public void setPayMessage(User user, Indent indent,String paymentId,String payerId){
		//通知用户支付成功
		//管理员通知 --订单生成
		Message message = new Message();
		message.setAccepter(1L);
		message.setCreateTime(new Date());
		message.setIsRead(0);
		message.setOrderId(indent.getOrderId());
		//待翻译
		message.setMsg("来自" + user.getUserName() + "的订单, " + orderTypeMap.get(indent.getOrderType()) + " 支付成功!");
		message.setUserId(user.getId());
		message.setUserName(user.getUserName());
		messageService.addMessage(message);

		//客户通知 --订单生成
		Message messageCustom = new Message();
		messageCustom.setAccepter(user.getId());
		messageCustom.setCreateTime(new Date());
		messageCustom.setIsRead(0);
		messageCustom.setOrderId(indent.getOrderId());
		//待翻译
		messageCustom.setMsg("Your order:" + indent.getOrderNum() +", " + orderTypeMap.get(indent.getOrderType()) + " payment successful！");
		messageCustom.setUserId(user.getId());
		messageCustom.setUserName(user.getUserName());
		messageService.addMessage(messageCustom);

		//记录支付成功日志
		PayLog payLog = new PayLog(JSONObject.toJSONString(indent),paymentId,payerId,indent.getOrderId(),new Date());
		payLogService.addPayLog(payLog);
		inDentService.changePayState(user.getId(),indent.getOrderId(),1);

		//用户付款总数增加
		User user2 = new User();
		user2.setId(user.getId());
		Integer total = user.getTotal();
		user2.setTotal(total == null ? 1:total+1);
		Double consume = user.getConsume();
		user2.setConsume(consume == null ? indent.getTotalPrice() : (new BigDecimal(consume).add(new BigDecimal(indent.getTotalPrice()))).doubleValue());
		userDao.updateByPrimaryKeySelective(user2);
	}

	private String generateBase64String(String clientCredentials) throws PayPalRESTException {
		String base64ClientID = null;
		byte[] encoded = null;
		try {
			encoded = Base64.encodeBase64(clientCredentials.getBytes("UTF-8"));
			base64ClientID = new String(encoded, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new PayPalRESTException(e.getMessage(), e);
		}
		return base64ClientID;
	}
}
